package com.cema.manage.pow;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import java.math.BigInteger;

/**
 * 工作量证明
 *
 * @author wangwei
 * @date 2018/02/04
 */
public class ProofOfWork {
    /**
     * 难度目标位
     */
    public static int TARGET_BITS = 12;

    /**
     * 难度目标值
     */
    private static BigInteger target;

    private Block block;

    private static ProofOfWork proofOfWork;

    public static void setTargetBits(int targetBits) {
        TARGET_BITS = targetBits;
        target = BigInteger.ONE.shiftLeft((256 - TARGET_BITS));
    }

    public static ProofOfWork SimpleBlock() {
        if (proofOfWork == null) {
            proofOfWork = new ProofOfWork();
        }
        return proofOfWork;
    }


    public ProofOfWork() {
        this.block = Block.newGenesisBlock();
        this.target = BigInteger.ONE.shiftLeft((256 - TARGET_BITS));
    }


    /**
     * 验证区块是否有效
     *
     * @return
     */
    public boolean validate(String nonce, String time) {
        byte[] data = this.prepareData(nonce, time);
        return new BigInteger(DigestUtils.sha256Hex(data), 16).compareTo(this.target) == -1;
    }

    /**
     * 准备数据
     * <p>
     * 注意：在准备区块数据时，一定要从原始数据类型转化为byte[]，不能直接从字符串进行转换
     *
     * @param nonce
     * @return
     */
    private byte[] prepareData(String nonce, String time) {
        byte[] prevBlockHashBytes = {};
        if (StringUtils.isNoneBlank(this.block.getPrevBlockHash())) {
            prevBlockHashBytes = new BigInteger(this.block.getPrevBlockHash(), 16).toByteArray();
        }
        return ByteUtils.merge(
                prevBlockHashBytes,
                ByteUtils.toBytes(Long.parseLong(time)),
                ByteUtils.toBytes(TARGET_BITS),
                ByteUtils.toBytes(Long.parseLong(nonce))
        );
    }
}
